package io.gitee.xjt2016.modules.common.utils.http;

import lombok.Data;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.http.*;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class RestTemplateUtil {
    private static class SingletonRestTemplate {
        static RestTemplate INSTANCE = getNewRestTemplate();
    }

    public static RestTemplate getInstance() {
        return SingletonRestTemplate.INSTANCE;
    }

    public static RestTemplate getNewRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
        for (HttpMessageConverter<?> httpMessageConverter : list) {
            if (httpMessageConverter instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(StandardCharsets.UTF_8);
                break;
            }
        }

//        RequestConfig requestConfig = RequestConfig.custom()
//                .setConnectTimeout(5000)//连接超时时间
//                .setConnectionRequestTimeout(3000)//从连接池中取连接的超时时间
//                .setSocketTimeout(10000)//数据传输过程中数据包之间间隔的最大时间
//                .build();

        //HttpClient默认连接池，最大连接是20个，最大同路由的是2个，也就是maxConnTotal是20，maxConnPerRoute是2。
        //maxConnTotal是同时间正在使用的最多的连接数
        //maxConnPerRoute是针对一个域名同时间正在使用的最多的连接数
//        HttpClient httpClient = HttpClientBuilder.create()
//                .setMaxConnTotal(1)
//                .setMaxConnPerRoute(1)
//                .setDefaultRequestConfig(requestConfig)
//                .build();
//        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);

        OkHttpClient okHttpClient = new OkHttpClient()
                .newBuilder()
//                .connectionPool(new ConnectionPool(10, 60, TimeUnit.SECONDS))
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .addInterceptor(new DynamicTimeoutInterceptor())
                .build();

        OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(okHttpClient);
        restTemplate.setRequestFactory(factory);
        return restTemplate;
    }

    public static String post(String url, Map<String, String> params) throws IOException {
        MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>(params.size());
        for (Map.Entry<String, String> entry : params.entrySet()) {
            List<String> list = new ArrayList<>(1);
            list.add(entry.getValue());
            multiValueMap.put(entry.getKey(), list);
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(multiValueMap, headers);
        ResponseEntity<String> response = RestTemplateUtil.getInstance().exchange(url, HttpMethod.POST, requestEntity, String.class);
        return response.getBody();
    }

    public static String get(String url, Map<String, String> params) throws IOException {
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
        params.forEach(builder::queryParam);
        return RestTemplateUtil.getInstance().getForObject(builder.build().encode().toUri(), String.class);
    }

    /**
     * 动态设置接口请求超时时间
     */
    public static class DynamicTimeoutInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            String requestUrl = request.url().toString();
//                return chain.withConnectTimeout(TimeOut.CLOSE_CONNECT, TimeUnit.SECONDS)
//                        .withReadTimeout(TimeOut.CLOSE_READ, TimeUnit.SECONDS)
//                        .proceed(request);

            return chain.proceed(request);
        }
    }


    public static class DynamicConstant {
        public static final Map<String, TimeoutConfig> domainMap = new HashMap<>();
        public static final Map<String, TimeoutConfig> urlMap = new HashMap<>();
    }

    @Data
    public static class TimeoutConfig {
        private int readTimeout = 5000;
        private int connectTimeout = 5000;
    }

    /**
     * 重试拦截器
     */
    public static class RetryInterceptor implements Interceptor {

        public int maxRetry = 2;//最大重试次数
        private int retryNum = 0;//假如设置为3次重试的话，则最大可能请求4次（默认1次+3次重试）

        public RetryInterceptor(int maxRetry) {
            this.maxRetry = maxRetry;
        }

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            System.out.println("retryNum=" + retryNum);
            Response response = chain.proceed(request);
            while (!response.isSuccessful() && retryNum < maxRetry) {
                retryNum++;
                System.out.println("retryNum=" + retryNum);
                response = chain.proceed(request);
            }
            return response;
        }
    }

}
